package com.eastfair.venuebooking.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.eastfair.auth.api.UserAccountServiceFeign;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.encrypt.RSAEncrypt;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ExcelUtils;
import com.eastfair.database.mybatis.typehandler.M9EncryptHandler;
import com.eastfair.database.mybatis.typehandler.TypeHandlerUtil;
import com.eastfair.venuebooking.dao.ContactMapper;
import com.eastfair.venuebooking.dto.ContactDTO;
import com.eastfair.venuebooking.dto.ContactQuery;
import com.eastfair.venuebooking.dto.ContactRefDTO;
import com.eastfair.venuebooking.dto.ContactRefQuery;
import com.eastfair.venuebooking.entity.Contact;
import com.eastfair.venuebooking.entity.ContactRef;
import com.eastfair.venuebooking.entity.CustomerMain;
import com.eastfair.venuebooking.enums.BirthdayQueryTypeEnum;
import com.eastfair.venuebooking.exceptioncode.VenueBookingExceptionCode;
import com.eastfair.venuebooking.service.*;
import com.eastfair.venuebooking.vo.ContactVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 业务实现类
 * 客户及线索联系人表
 * </p>
 *
 * @author linan
 * @date 2022-06-08
 */
@Slf4j
@Service
//@DS("#thread.tenant")
public class ContactServiceImpl extends SuperServiceImpl<ContactMapper, Contact> implements ContactService {

    private static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Resource
    private ContactMapper contactMapper;

    @Resource
    private ContactRefService contactRefService;

    @Resource
    private CustomerMainService customerMainService;

    @Resource
    private SaleClueService saleClueService;

    @Resource
    private UserAccountServiceFeign userAccountServiceFeign;

    @Resource
    private VenueBookingDictionaryService venueBookingDictionaryService;

    @Override
    protected R<Boolean> handlerSave(Contact model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }

    @Override
    public IPage<ContactVO> listContactVOs(PageParams<ContactQuery> pageParams) throws Exception {
        log.info("selectContactVOList - 分页查询联系人列表, pageParams={}", pageParams);
        IPage<Contact> page = pageParams.buildPage();
        ContactQuery query = pageParams.getModel();
        QueryWrapper<Contact> queryWrapper = createContactQueryWrapper(query);
        IPage<ContactVO> voPage = contactMapper.listContactVOs(page, queryWrapper);
        List<ContactVO> voList = voPage.getRecords();
        if (voList == null || voList.isEmpty()) {
            return voPage;
        }
        for (ContactVO contactVO: voList) {
            try {
                String mobile = contactVO.getMobile();
                String decryptMobile = TypeHandlerUtil.decrypt(mobile);
                contactVO.setMobile(decryptMobile);
            } catch (Exception e) {
               log.error("数据库解密失败", e);
            }
        }
        return voPage;
    }

    @Override
    public List<Contact> listByIds(List<Long> ids) {
        log.info("listByIds - ID列表查询联系人列表, ids={}", ids);
        QueryWrapper<Contact> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .lambda()
                .eq(Contact::getIsDeleted, BusinessConstant.DELETE_NO)
                .in(Contact::getId, ids)
                ;
        return list(queryWrapper);
    }

    @Override
    public List<ContactVO> listWaitCmsSync() {
        log.info("listWaitCmsSync - 查询待同步的联系人信息");
        QueryWrapper<Contact> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(Contact::getIsDeleted, BusinessConstant.DELETE_NO)
                .eq(Contact::getCmsSync, BusinessConstant.NO)
                .orderByAsc(Contact::getUpdateTime)
                .last("limit 10")
        ;
        List<Contact> list = list(queryWrapper);
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        return list
                .stream()
                .map(contact -> BeanUtil.toBean(contact, ContactVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public Contact getImportantContact(Long customerId, String subjectType) {
        ContactRefQuery query = new ContactRefQuery();
        query.setSubjectId(customerId);
        query.setSubjectType(subjectType);
        query.setImportant(true);
        ContactRef contactRef = contactRefService.getContactRef(query);
        if (contactRef != null) {
            return getById(contactRef.getContactId());
        }
        return null;
    }

    @Override
    public ContactVO getContactVOById(Long id) {
        log.info("selectContactVOById - id查询联系人, id={}", id);

        Contact contact = getById(id);
        if (contact == null) {
            throw BizException.wrap(VenueBookingExceptionCode.CONTACT_NOT_EXIST);
        }
        ContactVO contactVO = BeanUtil.toBean(contact, ContactVO.class);
        // 创建人/更新人信息
        R<String> createdByNameR = userAccountServiceFeign.getName(contact.getCreatedBy());
        contactVO.setCreatedByName(createdByNameR.getData());
        R<String> updatedByNameR = userAccountServiceFeign.getName(contact.getUpdatedBy());
        contactVO.setUpdatedByName(updatedByNameR.getData());
        // 客户信息
        CustomerMain customerMain = customerMainService.getCustomerByContactId(id);
        if (customerMain != null) {
            contactVO.setCustomerId(customerMain.getId());
            contactVO.setCustomerName(customerMain.getCustomerCnName());
        }
        return contactVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveContact(ContactDTO saveDTO) {
        log.info("saveContact - 保存联系人, saveDTO={}", saveDTO);

        Contact contact = BeanUtil.toBean(saveDTO, Contact.class);
        boolean saveContact = save(contact);
        saveDTO.setId(contact.getId());
        if (saveContact && saveDTO.getContactRef() != null) {
            ContactRef contactRef = BeanUtil.toBean(saveDTO.getContactRef(), ContactRef.class);
            contactRef.setContactId(contact.getId());
            return contactRefService.save(contactRef);
        }
        return saveContact;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateContact(ContactDTO updateDTO) {
        log.info("updateContact - 修改联系人, updateDTO={}", updateDTO);

        Contact contact = BeanUtil.toBean(updateDTO, Contact.class);
        contact.setCmsSync(BusinessConstant.NO);
        boolean updateContact = updateById(contact);
        ContactRefDTO contactRefUpdateDTO = updateDTO.getContactRef();
        if (contactRefUpdateDTO != null) {
            contactRefUpdateDTO.setContactId(contact.getId());
            QueryWrapper<ContactRef> queryWrapper = new QueryWrapper<>();
            queryWrapper.lambda()
                    .eq(ContactRef::getContactId, contact.getId())
                    .eq(ContactRef::getSubjectType, contactRefUpdateDTO.getSubjectType());
            contactRefService.remove(queryWrapper);
            ContactRef contactRef = BeanUtil.toBean(contactRefUpdateDTO, ContactRef.class);
            return contactRefService.save(contactRef);
        }
        return updateContact;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateCrmHasSync(List<Long> ids) {
        log.info("updateCmsHasSync - 更新联系人cms同步状态为已同步, ids={}", ids);
        List<Contact> list = listByIds(ids);
        if (list == null || list.isEmpty()) {
            return false;
        }
        for (Contact contact: list) {
            contact.setCmsSync(BusinessConstant.YES);
            updateById(contact);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeContactByIds(List<Long> ids) {
        log.info("removeContact - 移除联系人, ids={}", ids);
        if (contactRefService.existCustomerImportantContractRefByContactIds(ids)) {
            throw BizException.wrap(VenueBookingExceptionCode.CUS_EXIST_IMPORT_CONTACT_CAN_NOT_DELETE);
        }
        if (contactRefService.existOpportunityImportantContractRefByContactIds(ids)) {
            throw BizException.wrap(VenueBookingExceptionCode.BUS_EXIST_IMPORT_CONTACT_CAN_NOT_DELETE);
        }
        if (saleClueService.existSaleClueByContactId(ids)) {
            throw BizException.wrap(VenueBookingExceptionCode.CLUE_EXIST_CAN_NOT_DELETE);
        }
        // 移除联系人
        List<Contact> deleteContactList = listByIds(ids);
        boolean remove = removeByIdsOfLogic(deleteContactList);
        if (remove) {
            ContactRefDTO updateDTO = new ContactRefDTO();
            updateDTO.setContactIds(ids);
            return contactRefService.removeContactRef(updateDTO);
        }
        return false;
    }

    @Override
    public void exportContact(ContactQuery contactDTO, HttpServletResponse response) throws Exception {
        log.info("exportContact - 导出联系人, contactDTO={}", contactDTO);
        PageParams<ContactQuery> pageParams = new PageParams<>();
        pageParams.setModel(contactDTO);
        pageParams.setSize(5000);
        pageParams.setCurrent(1);
        IPage<ContactVO> voPage = listContactVOs(pageParams);
        List<ContactVO> voList = voPage.getRecords();
        if (voList == null || voList.isEmpty()) {
            return;
        }
        Map<String, String> roleDict = venueBookingDictionaryService.queryDictMap("CONTACT_ROLE");
        List<Map<String, Object>> rows = new ArrayList<>();
        for (ContactVO contactVO: voList) {
            TreeMap<String, Object> map = new TreeMap<>((o1, o2) -> 1);
            map.put("联系人姓名", contactVO.getContactName());
            map.put("关联客户", contactVO.getCustomerName());
            map.put("手机号码", contactVO.getMobile());
            LocalDate birthday = contactVO.getBirthday();
            String birthdayString = null;
            if (birthday != null) {
                birthdayString = birthday.format(dateTimeFormatter);
            }
            map.put("生日", birthdayString);
            String role = contactVO.getRole();
            String roleName = null;
            if (StrUtil.isNotBlank(role)) {
                roleName = roleDict.get(role);
            }
            map.put("角色", roleName);
            map.put("部门职务", contactVO.getPost());
            rows.add(map);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=联系人.xlsx");
        try (ServletOutputStream out = response.getOutputStream()) {
            ExcelUtils.export(rows, out);
        }
    }

    /**
     * 生成联系人查询.
     *
     * @param query ContactQuery.
     * @return QueryWrapper.
     */
    private QueryWrapper<Contact> createContactQueryWrapper(ContactQuery query) {
        QueryWrapper<Contact> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .and(StrUtil.isNotBlank(query.getKeyword()),
                        contactQueryWrapper ->
                                contactQueryWrapper.like("con.contact_name", query.getKeyword())
                                        .or()
                                        .like("cm.customer_cn_name", query.getKeyword())
                )
                .eq(StrUtil.isNotBlank(query.getRole()), "con.role", query.getRole())
                .eq("con.is_deleted", BusinessConstant.DELETE_NO)
        ;
        ContactRefQuery contactRefQuery = query.getContactRefQuery();
        if (contactRefQuery != null) {
            queryWrapper
                    .eq(StrUtil.isNotBlank(contactRefQuery.getSubjectType()),
                            "cr.subject_type", contactRefQuery.getSubjectType())
                    .eq(contactRefQuery.getSubjectId() != null,
                            "cr.subject_id", contactRefQuery.getSubjectId());
        }
        // 联系人生日查询
        List<String> birthdayList = getBirthdayList(query.getBirthdayQueryType());
        queryWrapper.and(!birthdayList.isEmpty(), contactQueryWrapper -> {
            for (String birthday : birthdayList) {
                contactQueryWrapper.like("date_format(con.birthday, '%m-%d')", birthday).or();
            }
        });
        return queryWrapper;
    }

    /**
     * 获取生日列表.
     *
     * @param birthdayPeriod birthdayPeriod.
     * @return 生日列表.
     */
    private List<String> getBirthdayList(String birthdayPeriod) {
        List<String> birthdayList = new ArrayList<>(16);
        if (StrUtil.isBlank(birthdayPeriod)) {
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.TODAY.getCode().equals(birthdayPeriod)) {
            String today = DateUtil.date().toString("MM-dd");
            birthdayList.add(today);
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.TOMORROW.getCode().equals(birthdayPeriod)) {
            String tomorrow = DateUtil.tomorrow().toString("MM-dd");
            birthdayList.add(tomorrow);
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.THIS_WEEK.getCode().equals(birthdayPeriod)) {
            Date now = new Date();
            DateTime beginDateTime = DateUtil.beginOfWeek(now);
            DateTime endDateTime = DateUtil.endOfWeek(now);
            getBirthdayList(beginDateTime, endDateTime, birthdayList);
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.NEXT_WEEK.getCode().equals(birthdayPeriod)) {
            Date now = DateUtil.nextWeek().toJdkDate();
            DateTime beginDateTime = DateUtil.beginOfWeek(now);
            DateTime endDateTime = DateUtil.endOfWeek(now);
            getBirthdayList(beginDateTime, endDateTime, birthdayList);
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.THIS_MONTH.getCode().equals(birthdayPeriod)) {
            Date now = new Date();
            DateTime beginDateTime = DateUtil.beginOfMonth(now);
            DateTime endDateTime = DateUtil.endOfMonth(now);
            getBirthdayList(beginDateTime, endDateTime, birthdayList);
            return birthdayList;
        }
        if (BirthdayQueryTypeEnum.NEXT_MONTH.getCode().equals(birthdayPeriod)) {
            Date now = DateUtil.nextMonth().toJdkDate();
            DateTime beginDateTime = DateUtil.beginOfMonth(now);
            DateTime endDateTime = DateUtil.endOfMonth(now);
            getBirthdayList(beginDateTime, endDateTime, birthdayList);
            return birthdayList;
        }
        return birthdayList;
    }

    /**
     * 获取生日列表.
     *
     * @param beginDateTime 开始时间
     * @param endDateTime   结束时间
     * @param birthdayList  生日列表
     */
    private void getBirthdayList(DateTime beginDateTime, DateTime endDateTime, List<String> birthdayList) {
        while (beginDateTime.isBefore(endDateTime)) {
            String queryDateTime = beginDateTime.toString("MM-dd");
            birthdayList.add(queryDateTime);
            beginDateTime = beginDateTime.offsetNew(DateField.HOUR_OF_DAY, 24);
        }
    }
}
